
package com.biqee.util;

import java.math.BigDecimal;

/**
 * BigDecimal类的运算工具类。
 * 所有浮点数的运算前都应该使用BigDecimal类封装，用本工具类来运算。
 *
 */
public class BigDecimalUtil {
	
	private BigDecimalUtil() {
		// ...
	}
	
	/**
	 * 转换NULL->0
	 * 
	 * 
	 * @param v
	 * @return
	 */
	public static BigDecimal null2Zero(BigDecimal v){
		return (v==null)?BigDecimal.ZERO:v;
	}
	
	/** 
     * 提供精确的加法运算。
     * 运算前先检查或格式化两个数字。
     * 参数为NULL,则自动转换为0
     *  
     * @param v1 被加数 
     * @param v2 加数 
     * @return 两个参数的和 
     */ 
    public static BigDecimal add(BigDecimal v1, BigDecimal v2){ 
    	return null2Zero(v1).add(null2Zero(v2)); 
    }
    
    /** 
     * 提供精确的加法运算。 
     * 运算前先检查或格式化两个数字。
     * 
     * @param v1 被加数 
     * @param v2 加数 
     * @return 两个参数的和 
     */ 
    public static BigDecimal add(String v1, String v2){ 
    	return add(new BigDecimal(v1), new BigDecimal(v2));
    }
    
    /** 
	 * 提供精确的减法运算。 
	 * 运算前先检查或格式化两个数字。
	 * 参数为NULL,则自动转换为0
	 * 
	 * @param v1 被减数 
	 * @param v2 减数 
	 * @return 两个参数的差 
	 */ 
	public static BigDecimal subtract(BigDecimal v1,BigDecimal v2){ 
	    return null2Zero(v1).subtract(null2Zero(v2));
	}
	
	/** 
	 * 提供精确的减法运算。 
	 * 运算前先检查或格式化两个数字。
	 * 
	 * @param v1 被减数 
	 * @param v2 减数 
	 * @return 两个参数的差 
	 */ 
	public static BigDecimal subtract(String v1, String v2){ 
	    return subtract(new BigDecimal(v1), new BigDecimal(v2));
	}
	
	/** 
	 * 提供精确的乘法运算。 
	 * 运算前先检查或格式化两个数字。
	 * 参数为NULL,则自动转换为0
	 * 
	 * @param v1 被乘数 
	 * @param v2 乘数 
	 * @return 两个参数的积 
	 */ 
	public static BigDecimal multiply(BigDecimal v1, BigDecimal v2){ 
	    return null2Zero(v1).multiply(null2Zero(v2)); 
	} 
	
	/** 
	 * 提供精确的乘法运算。 
	 * 运算前先检查或格式化两个数字。
	 * 
	 * @param v1 被乘数 
	 * @param v2 乘数 
	 * @return 两个参数的积 
	 */ 
	public static BigDecimal multiply(String v1, String v2){ 
	    return multiply(new BigDecimal(v1), new BigDecimal(v2)); 
	}
	
	/** 
	 * 提供（相对）精确的除法运算。当发生除不尽的情况时，保留scale位小数，数字舍入模式：roundingMode。 
	 * 运算前先检查或格式化两个数字。
	 * 被除数为NULL,则自动转换为0
	 * 
	 * @param v1 被除数 
	 * @param v2 除数
	 * @param scale 保留位数 
	 * @param roundingMode 舍入模式，如：四舍五入，取整舍入等
	 * @return 两个参数的商 
	 */ 
	public static BigDecimal divide(BigDecimal v1, BigDecimal v2, int scale, int roundingMode){ 
	    return null2Zero(v1).divide(v2, scale, roundingMode); 
	}
	
	/** 
	 * 提供（相对）精确的除法运算。当发生除不尽的情况时，保留scale位小数，数字舍入模式：roundingMode。 
	 * 运算前先检查或格式化两个数字。
	 * 
	 * @param v1 被除数 
	 * @param v2 除数
	 * @param scale 保留位数 
	 * @param roundingMode 舍入模式，如：四舍五入，取整舍入等
	 * @return 两个参数的商 
	 */ 
	public static BigDecimal divide(String v1, String v2, int scale, int roundingMode){ 
	    return divide(new BigDecimal(v1), new BigDecimal(v2), scale, roundingMode); 
	}
	
	/** 
	 * 提供（相对）精确的除法运算。当发生除不尽的情况时，保留两位位小数，数字舍入模式：四舍五入。 
	 * 运算前先检查或格式化两个数字。
	 * 
	 * @param v1 被除数 
	 * @param v2 除数
	 * @return 两个参数的商 
	 */ 
	public static BigDecimal defaultDivide(BigDecimal v1, BigDecimal v2){ 
	    return divide(v1, v2, 2, BigDecimal.ROUND_HALF_UP);
	}
	
	/** 
	 * 提供（相对）精确的除法运算。当发生除不尽的情况时，保留两位位小数，数字舍入模式：四舍五入。 
	 * 运算前先检查或格式化两个数字。
	 * 
	 * @param v1 被除数 
	 * @param v2 除数
	 * @return 两个参数的商 
	 */ 
	public static BigDecimal defaultDivide(String v1, String v2){ 
	    return defaultDivide(new BigDecimal(v1), new BigDecimal(v2));
	}
	
	/** 
	 * 提供精确的小数位处理。 
	 * 
	 * @param v 数字 
	 * @param scale 小数点后保留几位
	 * @param roundingMode 舍入模式，如：四舍五入，取整舍入等 
	 * @return 小数处理结果 
	 */ 
	public static BigDecimal round(BigDecimal v, int scale, int roundingMode){ 
	    return v.divide(BigDecimal.ONE, scale, roundingMode); 
	}
	/** 
	 * 提供精确的小数位处理。 
	 * 
	 * @param v 数字 
	 * @param scale 小数点后保留几位
	 * @param roundingMode 舍入模式，如：四舍五入，取整舍入等 
	 * @return 小数处理结果 
	 */ 
	public static BigDecimal round(String v, int scale, int roundingMode){ 
	    return new BigDecimal(v).divide(BigDecimal.ONE, scale, roundingMode); 
	}
	
	/** 
	 * 提供精确的小数位处理。保留两位位小数，数字舍入模式：四舍五入。 
	 * 
	 * @param v 数字 
	 * @return 小数处理结果 
	 */ 
	public static BigDecimal defaultRound(BigDecimal v){ 
	    return v.divide(BigDecimal.ONE, 2, BigDecimal.ROUND_HALF_UP); 
	}
	/** 
	 * 提供精确的小数位处理。保留两位位小数，数字舍入模式：四舍五入。 
	 * 
	 * @param v 数字 
	 * @return 小数处理结果 
	 */ 
	public static BigDecimal defaultRound(String v){ 
	    return new BigDecimal(v).divide(BigDecimal.ONE, 2, BigDecimal.ROUND_HALF_UP); 
	}
	
	/**
	 * 使用"+-*\"操作符，作两数运算
	 * 
	 * @author chun.fengch
	 * @date 2008-12-19
	 * 
	 * @param v1 操作数1
	 * @param v2 操作数2
	 * @param opt 操作符
	 * @return
	 */
	public static BigDecimal calc(BigDecimal v1, String opt, BigDecimal v2){
		BigDecimal rst = null;
		switch(opt.charAt(0)){
			case '+': rst = BigDecimalUtil.add(v1, v2);break;
			case '-': rst = BigDecimalUtil.subtract(v1, v2);break;
			case '*': rst = BigDecimalUtil.multiply(v1, v2);break;
			case '\\': rst = BigDecimalUtil.defaultDivide(v1, v2);break;
		}
		return rst;
	}
	
	/**
	 * 按照输入顺序，简单作"+-*\"四则运算
	 * 
	 * @author chun.fengch
	 * @date 2008-12-19
	 * 
	 * @param arr
	 * @param express
	 * @return
	 */
	public static BigDecimal arth(Object...objects){
		if(objects==null || objects.length<=0) return null;
		
		BigDecimal result = null;
		for (int i = 1; i < objects.length; i=i+2) {
			if(i==1){
				result = BigDecimalUtil.calc((BigDecimal)objects[i-1],(String)objects[i],(BigDecimal)objects[i+1]);
			}else{
				result = BigDecimalUtil.calc(result,(String)objects[i],(BigDecimal)objects[i+1]);
			}			
		}
		
		return result;
	}
}